#define _CRT_SECURE_NO_WARNINGS

#define _WINSOCK_DEPRECATED_NO_WARNINGS


#include <stdio.h>
#include <stdlib.h>

#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

/*--------------------------------------------------------------------------*/
#define MAX_MSG_SIZE 1024
BYTE  bSendBuf[1500];
struct sockaddr_in gDestSocketAddr;



/*--------------------------------------------------------------------------*/
void printMsg_WSAGetLastError()
{
    LPVOID lpMsgBuf;
    int nErrorCode;

    nErrorCode = WSAGetLastError();
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        nErrorCode,
        0, //Language Identifiers 0x0804, // zh-ch:0x0804,en-us:0x0409,
        (LPTSTR) &lpMsgBuf,
        0,
        NULL
    );
    printf("WSAGetLastError()=%d, %s\n", nErrorCode, lpMsgBuf);
    LocalFree( lpMsgBuf );
}
/*--------------------------------------------------------------------------*/
int getLocalSocketAddrName(int socketFd)
{
    struct sockaddr_in SocketAddr;
    int nLen;
    int nRet;
      
    memset(&SocketAddr, 0, sizeof(struct sockaddr_in) );
    nLen = sizeof(struct sockaddr_in);
    nRet = getsockname ( socketFd, (SOCKADDR *)&SocketAddr, &nLen );
    if( 0 == nRet )
    {
        printf("socketfd=%d local[ip=%d.%d.%d.%d,port=%d]\n", 
            socketFd,
            *( (BYTE *)&SocketAddr.sin_addr     ),
            *( (BYTE *)&SocketAddr.sin_addr + 1 ),
            *( (BYTE *)&SocketAddr.sin_addr + 2 ),
            *( (BYTE *)&SocketAddr.sin_addr + 3 ),
            ntohs(SocketAddr.sin_port)  );
        return 0;
    }
    else
    {
        printf("socketfd=%d,getsockname failure: ",socketFd);
        printMsg_WSAGetLastError();
        return -1;
    }
}
/*--------------------------------------------------------------------------*/
int getPeerSocketAddrName(int socketFd)
{
    struct sockaddr_in SocketAddr;
    int nLen;
    int nRet;
      
    memset(&SocketAddr, 0, sizeof(struct sockaddr_in) );
    nLen = sizeof(struct sockaddr_in);
    nRet = getpeername ( socketFd, (SOCKADDR *)&SocketAddr, &nLen );
    if( 0 == nRet )
    {
        printf("socketfd=%d peer[ip=%d.%d.%d.%d,port=%d]\n", 
            socketFd,
            *( (BYTE *)&SocketAddr.sin_addr     ),
            *( (BYTE *)&SocketAddr.sin_addr + 1 ),
            *( (BYTE *)&SocketAddr.sin_addr + 2 ),
            *( (BYTE *)&SocketAddr.sin_addr + 3 ),
            ntohs(SocketAddr.sin_port)  );
        return 0;
    }
    else
    {
        printf("socketfd=%d,getpeername failure: ",socketFd);
        printMsg_WSAGetLastError();
        return -1;
    }   
}
/*--------------------------------------------------------------------------*/
int WINAPI threadDataSocketRecv(LPVOID lpParam)
{
    BYTE  bRcvBuf[1500];
    int clientfd;
    int nBytesRead;
   
    clientfd = (int)lpParam;
    printf("socketfd=%d:thread-data-socket-receive startup\n", clientfd);    

    while(1)
    {        
        memset(bRcvBuf,0,1500);
        nBytesRead = recv( clientfd, bRcvBuf, MAX_MSG_SIZE, 0);
        if( 0 >= nBytesRead )
        {
            printf("socketfd=%d,recv failure: ", clientfd);
            printMsg_WSAGetLastError();
            break;
        }
        else
        {
            getLocalSocketAddrName(clientfd);
            getPeerSocketAddrName(clientfd);
            printf("socketfd=%d, recv msglen=%d, msg=", clientfd, nBytesRead );
            printf("%s\n", bRcvBuf);
        }
    }

    printf("socketfd=%d:thread-data-socket-receive exit\n",clientfd); 

    return 0;
}
/*--------------------------------------------------------------------------*/
int WINAPI threadListenSocketAccept(LPVOID lpParam)
{
    int clientfd;
    int listenSocketFd;
    
    listenSocketFd = (int)lpParam;
    
    printf("thread-listen-socket-accept=%d startup\n", listenSocketFd);
    while(1)
    {   
        clientfd = accept(listenSocketFd, NULL, NULL);
        if( clientfd < 0 )
        {
            printf("socketfd=%d,accept failure: ", listenSocketFd);
            printMsg_WSAGetLastError();
            break;
        }
        else
        {
            printf("socket accept success, new client coming,clientfd=%d\n",clientfd);        
            getLocalSocketAddrName(clientfd);
            getPeerSocketAddrName(clientfd);
        }
     
        CreateThread( (LPSECURITY_ATTRIBUTES) NULL,
                 0,
                 (LPTHREAD_START_ROUTINE) threadDataSocketRecv,
                 (LPVOID)clientfd,
                 0, NULL );
        printf("create thread : threadDataSocketRecv for clientfd=%d\n",clientfd);
    }


    return 0;
}
/*--------------------------------------------------------------------------*/
int main()
{
    WSADATA wsaData;
    int nRetCode;
    int socketfd = -1;
    int nSendDataFd;
    int nBytesTx;
    char c;

    nRetCode = WSAStartup(0x0202, &wsaData);
    if (nRetCode != 0)
    {
        printf("WSAStartup failed with error: %d\n", nRetCode);
        return -1;
    }
    else
    {
        printf("WSAStartup sucess to startup\n");
    }


    socketfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(socketfd < 0)
    {
        printf("socket create failure,reason:\n");
        printMsg_WSAGetLastError();

        WSACleanup();
        return -1;
    }
    else
    {
        printf("socket create success,socketfd=%d\n",socketfd);
    }

    memset(&gDestSocketAddr, 0, sizeof(struct sockaddr_in) );
    gDestSocketAddr.sin_family = AF_INET;
    gDestSocketAddr.sin_port = htons(9999);
    gDestSocketAddr.sin_addr.s_addr = inet_addr("0.0.0.0");  
    nRetCode = bind( socketfd, (SOCKADDR *)&gDestSocketAddr, sizeof(SOCKADDR) );
    if( 0 != nRetCode)
    {
        printf("socket bind failure,reason:\n");
        printMsg_WSAGetLastError();

        closesocket(socketfd);
        WSACleanup();
        return -1;
    }
    else
    {
        printf("socket bind success\n");
    }  

    nRetCode = listen(socketfd, SOMAXCONN);
    if( 0 != nRetCode )
    {
        printf("socket listen failure,reason:\n");
        printMsg_WSAGetLastError();

        closesocket(socketfd);
        WSACleanup();
        return -1;
    }
    

    CreateThread( (LPSECURITY_ATTRIBUTES) NULL,
                         0,
                         (LPTHREAD_START_ROUTINE) threadListenSocketAccept,
                         (LPVOID)socketfd,
                         0, NULL );
    printf("create thread: threadListenSocketAccept\n");
    
    Sleep(1000);


    while(1)
    {
        fflush(stdin);
        c = getchar();
        
        printf("please input client(socketfd) you want to send:\n");
        scanf("%d",&nSendDataFd);
        
        printf("please input msg you want to send:\n");
        memset(bSendBuf, 0, 1500);
        scanf("%s",bSendBuf);

        nBytesTx = send(nSendDataFd, bSendBuf, strlen(bSendBuf), 0);
        if(0 >= nBytesTx)
        {
            printf("socketfd=%d send failure,reason:\n", nSendDataFd);
            printMsg_WSAGetLastError();
			break;
        }
        else
        {
            printf("socketfd=%d: send msglen=%d\n", nSendDataFd, nBytesTx);
        }
                
    }

    WSACleanup();
    
    return 0;
}